package com.yht.weblog.admin.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.yht.weblog.admin.convert.ArticleDetailConvert;
import com.yht.weblog.admin.event.DeleteArticleEvent;
import com.yht.weblog.admin.event.PublishArticleEvent;
import com.yht.weblog.admin.event.UpdateArticleEvent;
import com.yht.weblog.admin.model.vo.article.*;
import com.yht.weblog.admin.service.AdminArticleService;
import com.yht.weblog.common.domain.dos.*;
import com.yht.weblog.common.domain.mapper.*;
import com.yht.weblog.common.enums.ResponseCodeEnum;
import com.yht.weblog.common.exception.BizException;
import com.yht.weblog.common.utils.PageResponse;
import com.yht.weblog.common.utils.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: yht
 * @date: 2024/1/2 22:46
 * @description:
 **/
@Service
@Slf4j
public class AdminArticleServiceImpl implements AdminArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private ArticleContentMapper articleContentMapper;
    @Autowired
    private ArticleCategoryRelMapper articleCategoryRelMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private ArticleTagRelMapper articleTagRelMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 发布文章
     *
     * @param publishArticleReqVO 发布文章请求参数
     * @return 发布文章响应结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response publishArticle(PublishArticleReqVO publishArticleReqVO) {
        // 将VO对象转换为ArticleDO对象并保存到数据库
        ArticleDO articleDO = ArticleDO.builder().title(publishArticleReqVO.getTitle()).cover(publishArticleReqVO.getCover()).summary(publishArticleReqVO.getSummary()).createTime(LocalDateTime.now()).updateTime(LocalDateTime.now()).build();
        articleMapper.insert(articleDO);
        // 获取刚插入的记录的主键ID
        Long articleId = articleDO.getId();
        // 将VO对象转换为ArticleContentDO对象并保存到数据库
        ArticleContentDO articleContentDO = ArticleContentDO.builder().articleId(articleId).content(publishArticleReqVO.getContent()).build();
        articleContentMapper.insert(articleContentDO);
        Long categoryId = publishArticleReqVO.getCategoryId();
        // 根据ID查询分类信息
        CategoryDO categoryDO = categoryMapper.selectById(categoryId);
        if (Objects.isNull(categoryDO)) {
            log.warn("===> 分类不存在，categoryId:{}", categoryId);
            throw new BizException(ResponseCodeEnum.CATEGORY_NOT_EXISTED);
        }
        // 构建文章与分类的关系并保存到数据库
        ArticleCategoryRelDO articleCategoryRelDO = ArticleCategoryRelDO.builder().articleId(articleId).categoryId(categoryId).build();
        articleCategoryRelMapper.insert(articleCategoryRelDO);
        // 保存文章和标签的关联关系
        List<String> publishTags = publishArticleReqVO.getTags();
        insertTags(articleId, publishTags);

        eventPublisher.publishEvent(new PublishArticleEvent(this, articleId));
        return Response.success();
    }

    /**
     * 删除文章
     *
     * @param deleteArticleReqVO 删除文章请求参数
     * @return 删除文章响应结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response deleteArticle(DeleteArticleReqVO deleteArticleReqVO) {
        Long articleId = deleteArticleReqVO.getId();
        // 根据 ID 删除文章
        articleMapper.deleteById(articleId);
        // 根据 ID 删除文章内容
        articleContentMapper.deleteByArticleId(articleId);
        // 根据 ID 删除文章分类关联
        articleCategoryRelMapper.deleteByArticleId(articleId);
        // 根据 ID 删除文章标签关联
        articleTagRelMapper.deleteByArticleId(articleId);

        eventPublisher.publishEvent(new DeleteArticleEvent(this, articleId));

        return Response.success();

    }

    /**
     * 查询文章分页数据
     *
     * @param findArticlePageListReqVO 查询文章分页数据请求参数
     * @return 查询文章分页数据响应结果
     */
    @Override
    public Response findArticlePageList(FindArticlePageListReqVO findArticlePageListReqVO) {
        // 当前页码
        Long current = findArticlePageListReqVO.getCurrent();
        // 每页大小
        Long size = findArticlePageListReqVO.getSize();
        // 文章标题
        String title = findArticlePageListReqVO.getTitle();
        // 开始日期
        LocalDate startDate = findArticlePageListReqVO.getStartDate();
        // 结束日期
        LocalDate endDate = findArticlePageListReqVO.getEndDate();
        // 根据条件查询文章分页数据
        Page<ArticleDO> articleDOPage = articleMapper.selectPageList(current, size, title, startDate, endDate);
        // 获取文章列表
        List<ArticleDO> articleDOS = articleDOPage.getRecords();
        // 响应结果列表
        List<FindArticlePageListRspVO> vos = null;

        // 如果文章列表不为空
        if (!CollectionUtils.isEmpty(articleDOS)) {
            // 将文章列表转换为FindArticlePageListRspVO对象列表
            vos = articleDOS.stream()
                    .map(articleDO -> FindArticlePageListRspVO.builder()
                            .id(articleDO.getId())
                            .title(articleDO.getTitle())
                            .cover(articleDO.getCover())
                            .createTime(articleDO.getCreateTime())
                            .build())
                    .collect(Collectors.toList());
        }

        // 返回查询结果
        return PageResponse.success(articleDOPage, vos);
    }


    /**
     * 保存文章和标签的关联关系
     *
     * @param articleId   文章ID
     * @param publishTags 标签列表
     */
    private void insertTags(Long articleId, List<String> publishTags) {
        // 初始化变量
        List<String> notExistTags = null;
        List<String> existedTags = null;
        // 查询所有标签信息
        List<TagDO> tagDOS = tagMapper.selectList(null);
        if (CollectionUtils.isEmpty(tagDOS)) {
            notExistTags = publishTags;
        } else {
            // 将标签ID转换为列表
            List<String> tagIds = tagDOS.stream().map(tagDO -> String.valueOf(tagDO.getId())).collect(Collectors.toList());
            // 过滤已存在的标签
            existedTags = publishTags.stream().filter(publishTag -> tagIds.contains(publishTag)).collect(Collectors.toList());
            // 过滤不存在的标签
            notExistTags = publishTags.stream().filter(publishTag -> !tagIds.contains(publishTag)).collect(Collectors.toList());
            // 根据标签名称和ID构建映射关系
            Map<String, Long> tagNameIdMap = tagDOS.stream().collect(Collectors.toMap(tagDO -> tagDO.getName().toLowerCase(), TagDO::getId));
            // 根据不存在的标签名称查询是否存在相同名称的标签，若存在则删除该标签并添加到已存在的标签列表中
            Iterator<String> iterator = notExistTags.iterator();
            while (iterator.hasNext()) {
                String notExistTag = iterator.next();
                if (tagNameIdMap.containsKey(notExistTag.toLowerCase())) {
                    iterator.remove();
                    existedTags.add(String.valueOf(tagNameIdMap.get(notExistTag.toLowerCase())));
                }
            }
        }
        // 若存在已存在的标签，则批量保存文章和标签的关系
        if (!CollectionUtils.isEmpty(existedTags)) {
            ArrayList<ArticleTagRelDO> articleTagRelDOS = Lists.newArrayList();
            existedTags.forEach(tagId -> {
                ArticleTagRelDO articleTagRelDO = ArticleTagRelDO.builder()
                        .articleId(articleId)
                        .tagId(Long.valueOf(tagId))
                        .build();
                articleTagRelDOS.add(articleTagRelDO);
            });
            articleTagRelMapper.insertBatchSomeColumn(articleTagRelDOS);
        }
        // 若存在不存在的标签，则批量保存文章和标签的关系
        if (!CollectionUtils.isEmpty(notExistTags)) {
            ArrayList<ArticleTagRelDO> articleTagRelDOS = Lists.newArrayList();
            notExistTags.forEach(tagName -> {
                // 新增标签并保存
                TagDO tagDO = TagDO.builder()
                        .name(tagName)
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .build();
                tagMapper.insert(tagDO);
                // 构建文章和标签的关系并保存
                ArticleTagRelDO articleTagRelDO = ArticleTagRelDO.builder()
                        .articleId(articleId)
                        .tagId(tagDO.getId())
                        .build();
                articleTagRelDOS.add(articleTagRelDO);
            });
            // 批量保存文章和标签的关系
            articleTagRelMapper.insertBatchSomeColumn(articleTagRelDOS);
        }
    }

    /**
     * 查找文章详情
     *
     * @param findArticleDetailReqVO 文章详情查询请求对象
     * @return 文章详情响应对象
     */
    @Override
    public Response findArticleDetail(FindArticleDetailReqVO findArticleDetailReqVO) {
        // 获取文章ID
        Long articleId = findArticleDetailReqVO.getId();
        // 根据文章ID查询文章对象
        ArticleDO articleDO = articleMapper.selectById(articleId);
        // 若文章对象为空，则提示文章不存在并抛出业务异常
        if (Objects.isNull(articleDO)) {
            log.warn("===> 文章不存在，articleId:{}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }
        // 根据文章ID查询文章内容对象
        ArticleContentDO articleContentDO = articleContentMapper.selectByArticleId(articleId);
        // 根据文章ID查询文章分类关系对象
        ArticleCategoryRelDO articleCategoryRelDO = articleCategoryRelMapper.selectByArticleId(articleId);
        // 根据文章ID查询文章标签关系列表
        List<ArticleTagRelDO> articleTagRelDOS = articleTagRelMapper.selectByArticleId(articleId);
        // 提取文章标签ID列表
        List<Long> tags = articleTagRelDOS.stream().map(ArticleTagRelDO::getTagId).collect(Collectors.toList());
        // 将文章对象转换为文章详情响应对象
        FindArticleDetailRspVO findArticleDetailRspVO = ArticleDetailConvert.INSTANCE.convertDO2VO(articleDO);
        findArticleDetailRspVO.setContent(articleContentDO.getContent());
        findArticleDetailRspVO.setCategoryId(articleCategoryRelDO.getCategoryId());
        findArticleDetailRspVO.setTagIds(tags);

        // 返回文章详情响应对象
        return Response.success(findArticleDetailRspVO);
    }

    /**
     * 更新文章
     *
     * @param updateArticleReqVO 更新文章请求参数
     * @return 更新文章响应结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response updateArticle(UpdateArticleReqVO updateArticleReqVO) {
        // 获取文章ID
        Long articleId = updateArticleReqVO.getId();

        // 根据请求参数构建文章DO对象
        ArticleDO articleDO = ArticleDO.builder()
                .id(articleId)
                .title(updateArticleReqVO.getTitle())
                .cover(updateArticleReqVO.getCover())
                .summary(updateArticleReqVO.getSummary())
                .updateTime(LocalDateTime.now())
                .build();

        // 更新文章信息
        int count = articleMapper.updateById(articleDO);

        // 如果更新数量为0，说明文章不存在
        if (count == 0) {
            log.warn("===> 该文章不存在，articleId:{}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        // 更新文章内容
        ArticleContentDO articleContentDO = ArticleContentDO.builder()
                .articleId(articleId)
                .content(updateArticleReqVO.getContent())
                .build();

        articleContentMapper.updateByArticleId(articleContentDO);

        // 获取文章所属分类ID
        Long categoryId = updateArticleReqVO.getCategoryId();

        // 根据分类ID查询分类信息
        CategoryDO categoryDO = categoryMapper.selectById(categoryId);

        // 如果分类信息为空，说明分类不存在
        if (Objects.isNull(categoryDO)) {
            log.warn("===> 分类不存在，categoryId:{}", categoryId);
            throw new BizException(ResponseCodeEnum.CATEGORY_NOT_EXISTED);
        }

        // 删除文章与分类的关系
        articleCategoryRelMapper.deleteByArticleId(articleId);

        // 构建文章与分类的关系DO对象
        ArticleCategoryRelDO articleCategoryRelDO = ArticleCategoryRelDO.builder()
                .articleId(articleId)
                .categoryId(categoryId)
                .build();

        // 插入文章与分类的关系
        articleCategoryRelMapper.insert(articleCategoryRelDO);

        // 删除文章与标签的关系
        articleTagRelMapper.deleteByArticleId(articleId);

        // 获取文章所属标签列表
        List<String> publishTags = updateArticleReqVO.getTags();

        // 插入文章与标签的关系
        insertTags(articleId, publishTags);

        // 发布文章修改事件
        eventPublisher.publishEvent(new UpdateArticleEvent(this, articleId));

        return Response.success();
    }

}